package org.bultreebank.extractor;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.bultreebank.document_repository.impl.IndexesDocumentsImpl;
import org.bultreebank.index.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import clark.dom.impl.DOMFactory;
import clark.loader.Loader;
import clark.xpath.MainXPath;


/**
 * The content extractor implementations should have as a parameter a
 * StorageManager implementation object. In order to be retrieve a 
 * relevant document content, the physical location and ways for
 * accessing documents should be known. A Storage Manager is
 * responsible for that. 
 * 
 * @author Aneliya Ticheva
 *
 */
public class RelevantContentExrtactor implements Extractor, Constants
{

	private IndexesDocumentsImpl documentsManager;
	public RelevantContentExrtactor(IndexesDocumentsImpl documentsManager)
	{
		this.documentsManager = documentsManager;
	}
	@Override
	public Document getFormatedDocument(String[] matchingDocIDs)throws Exception  {
		Document resultDoc = DOMFactory.getEmptyDocument();
		Element root = resultDoc.createElement("result");
		resultDoc.appendChild(root);
		for (String matchingDocID: matchingDocIDs)
		{
			Document doc = null;
			if (matchingDocID.equals(EMPTY_STR))
				continue;
			int contextEnd = matchingDocID.indexOf(SPEC_CHAR);
			String context = matchingDocID.substring(0, contextEnd);
			Element contextElem = resultDoc.createElement(CONTEXT);
			root.appendChild(contextElem);
			contextElem.setAttribute(CONTEXT, context);
			String docIDs = matchingDocID.substring(contextEnd + SPEC_CHAR.length());
			StringTokenizer st = new StringTokenizer(docIDs);
			while (st.hasMoreTokens())
			{
				matchingDocID = st.nextToken();
				String xpath = getExtractionXPath(matchingDocID);
				if (xpath == null)
				    doc = documentsManager.getStorageManager().retrieveDocument(matchingDocID);
				else
					doc = documentsManager.getStorageManager().retrieveDocument(getInternalDocID(matchingDocID));
			    Element docElem = resultDoc.createElement("document");
				docElem.setAttribute("id", matchingDocID);
				contextElem.appendChild(docElem);
				if (xpath != null)
				{
					List<Node> matchParts = MainXPath.processXPath("//" +xpath,  doc.getDocumentElement());
					for (Node n: matchParts)
					{
						Node adopted = Loader.adoptSubtree(resultDoc, n);
						docElem.appendChild(adopted);
					}
				}
				else
				{
					Node adopted = Loader.adoptSubtree(resultDoc, doc.getDocumentElement());
					docElem.appendChild(adopted);
				}
			}
		}
		return resultDoc;
	}
	private String getInternalDocID(String matchingDocID)
	{
		int index = matchingDocID.indexOf(UNDERSCORE);
		if (index < 0)
			return matchingDocID;
		return matchingDocID.substring(0, index);
	}
	private String getExtractionXPath(String matchingDocID)
	{
		if (matchingDocID.indexOf(UNDERSCORE) == -1)
			return null;
		String s = matchingDocID.substring(matchingDocID.indexOf(UNDERSCORE) + 1).replaceAll("#", "[").replaceAll(UNDERSCORE, "] ") + "]";
		return s.replaceAll(" ", LEFT_SLASH);
	}
	@Override
	public Map<String, Map<String, Set<String>>> getFormattedResultList(String[] matchingDocIDs)
			throws Exception
	{
		Map<String, Map<String, Set<String>>> result = new HashMap<String, Map<String,Set<String>>>();
		for (int i = 0; i < matchingDocIDs.length; i++)
		{
			String contextIDs = matchingDocIDs[i];
			int endContextIndex = contextIDs.indexOf(SPEC_CHAR);
			String context = contextIDs.substring(0, endContextIndex);
			String IDs = contextIDs.substring(endContextIndex + SPEC_CHAR.length());
			Map<String, Set<String>> contextList = new LinkedHashMap<String, Set<String>>();
			StringTokenizer st = new  StringTokenizer(IDs);
			while (st.hasMoreElements())
			{
				String ID = st.nextToken();
				String internalDocID = getInternalDocID(ID);
				String usersDocID = documentsManager.getUserDocID(internalDocID);
				Set<String> contextParts = new LinkedHashSet<String>();
				if (contextList.containsKey(usersDocID))
				{
					 contextParts = contextList.get(usersDocID);
					String xpath = getExtractionXPath(ID);
					if (xpath != null)
						contextParts.add(xpath);
				}
				else
				{
					String xpath = getExtractionXPath(ID);
					if (xpath != null)
						contextParts.add(xpath);
				}
				contextList.put(usersDocID, contextParts);
				result.put(context, contextList);
			}
		}
		return result;	
	}

}
